package com.szsh.aiot.common.utils;

import com.google.gson.Gson;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RandomStringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

/**
 * 加解密工具
 */
public class EncryptUtil {

    /** AES加密 */
    private static final String AES = "AES";
    /** AES keySize */
    private static final int AES_KEY_SIZE = 128;
    /** AES加密 */
    private static final String AES_ECB_PKCS_5 = "AES/ECB/PKCS5Padding";
    /** CBC加密模式 */
    private static final String AES_CBC_PKCS_5 = "AES/CBC/PKCS5Padding";
    /** DES加密 */
    private static final String DES = "DES";
    /** RSA加密 */
    private static final String RSA = "RSA";
    /** RSA keySize */
    public static final int RSA_KEY_SIZE_1024 = 1024;
//    public static final int RSA_KEY_SIZE_2048 = 2048;
    private static final int RSA_KEY_SIZE = 4096;
//    /** RSA最大加密明文大小 */
//    private static final int MAX_ENCRYPT_BLOCK = RSA_KEY_SIZE / 8 - 11;
//    /** RSA最大解密密文大小 */
//    private static final int MAX_DECRYPT_BLOCK = RSA_KEY_SIZE / 8;
    /** HmacSHA1 */
    private static final String HMAC_SHA1 = "HmacSHA1";
    /** SHA1WithRSA */
    private static final String SHA_1_WITH_RSA = "SHA1WithRSA";

    /**
     * AES/ECB/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param base64Key  bas64后密钥
     * @return 加密数据(经过base64转换), 返回null表示输入数据有误
     */
    public static String encryptAESBase64String(String data, String base64Key) throws Exception {
        if (isEmpty(data) || isEmpty(base64Key)) {
            return null;
        }
        return Base64.encodeBase64String(encryptAESByBase64Key(data, base64Key));
    }

    /**
     * AES/ECB/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param base64Key  bas64后密钥
     * @return 加密数据, 返回null表示输入数据有误
     */
    public static byte[] encryptAESByBase64Key(String data, String base64Key) throws Exception {
        if (isEmpty(data) || isEmpty(base64Key)) {
            return null;
        }
        return encryptAES(data, toKey(base64Key, AES));
    }

    public static void main(String[] args) throws Exception {

      Map<String, Object> baseMap = new HashMap<>();
        Map<String, Object> innerpara = new HashMap<>();
        String sequenceNo = UUID.randomUUID().toString().replace("-","");

        baseMap.put("sequenceNo",sequenceNo);
        baseMap.put("appId","289a1c91357a44f2851b481acc68fbde");
        baseMap.put("version",1.0);
        innerpara.put("sequenceNo",sequenceNo);
        innerpara.put("timestamp",new Date().getTime());
        innerpara.put("broadbandNO","01026831166");
        innerpara.put("phone","15366188232");
        innerpara.put("tyAccount","15366188232");
       // innerpara.put("eventType","All");

        innerpara.put("gatewayMac","28937D1352EA");
        innerpara.put("operaType","4");
        String data = new Gson().toJson(innerpara);
        System.out.println("请求参数data:     "+data);
        data = encryptAESBase64String(data,"CcFOSZeWVmPw+EHALSlDqg==");
        baseMap.put("data",data);

        String signatureSecret = "uS4EbP9nZ6";
        String signature = DigestUtils.md5Hex(sequenceNo + data + signatureSecret);
        baseMap.put("signature",signature);

        System.out.println("请求参数"+new Gson().toJson(baseMap));
    }

    /**
     * AES/ECB/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return 加密数据, 返回null表示输入数据有误
     */
    public static byte[] encryptAES(String data, String key) throws Exception {
        if (isEmpty(data) || isEmpty(key)) {
            return null;
        }
        return encryptAES(data, toKey(key.getBytes(StandardCharsets.UTF_8), AES));
    }

    /**
     * AES/ECB/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return 加密数据, 返回null表示输入数据有误
     */
    public static byte[] encryptAES(String data, Key key) throws Exception {
        if (isEmpty(data) || null == key) {
            return null;
        }
        return encryptAES(data.getBytes(StandardCharsets.UTF_8), key);
    }

    /**
     * AES/ECB/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return 加密数据, 返回null表示输入数据有误
     */
    public static byte[] encryptAES(byte[] data, Key key) throws Exception {
        if (isEmpty(data) || null == key) {
            return null;
        }
        // 实例化
        Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5);
        // 初始化,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, key);
        // 执行操作
        return cipher.doFinal(data);
    }


    /**
     * AES/ECB/PKCS5Padding解密
     *
     * @param base64Data base64后待解密数据
     * @param base64Key  bas64后密钥
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static String decryptAESByBase64Key(String base64Data, String base64Key) throws Exception {
        if (isEmpty(base64Data) || isEmpty(base64Key)) {
            return null;
        }
        byte[] bytes = decryptAES(Base64.decodeBase64(base64Data), toKey(base64Key, AES));
        if (null == bytes) {
            return null;
        }
        return new String(bytes, StandardCharsets.UTF_8);
    }

    /**
     * AES/ECB/PKCS5Padding解密
     *
     * @param base64Data base64后待解密数据
     * @param key  密钥
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static byte[] decryptAES(String base64Data, String key) throws Exception {
        if (isEmpty(base64Data) || isEmpty(key)) {
            return null;
        }
        return decryptAES(Base64.decodeBase64(base64Data), toKey(key.getBytes(StandardCharsets.UTF_8), AES));
    }

    /**
     * AES/ECB/PKCS5Padding解密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static byte[] decryptAES(byte[] data, Key key) throws Exception {
        if (isEmpty(data) || null == key) {
            return null;
        }
        // 实例化
        Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5);
        // 初始化,设置为加密模式
        cipher.init(Cipher.DECRYPT_MODE, key);
        // 执行操作
        return cipher.doFinal(data);
    }


    /**
     * AES/CBC/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param base64Key    bas64后密钥
     * @param base64ivKey  bas64后偏移量
     * @return 加密数据(经过base64转换), 返回null表示输入数据有误
     */
    public static String encryptAESBase64String(String data, String base64Key, String base64ivKey) throws Exception {
        if (isEmpty(data) || isEmpty(base64Key) || isEmpty(base64ivKey)) {
            return null;
        }
        return Base64.encodeBase64String(encryptAESByBase64Key(data, base64Key, base64ivKey));
    }

    /**
     * AES/CBC/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param base64Key  bas64后密钥
     * @param base64ivKey  bas64后偏移量
     * @return 加密数据, 返回null表示输入数据有误
     */
    public static byte[] encryptAESByBase64Key(String data, String base64Key, String base64ivKey) throws Exception {
        if (isEmpty(data) || isEmpty(base64Key) || isEmpty(base64ivKey)) {
            return null;
        }
        return encryptAES(data, toKey(base64Key, AES), Base64.decodeBase64(base64ivKey));
    }

    /**
     * AES/CBC/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @param iv   偏移量
     * @return 加密数据, 返回null表示输入数据有误
     */
    public static byte[] encryptAES(String data, String key, byte[] iv) throws Exception {
        if (isEmpty(data) || isEmpty(key) || isEmpty(iv)) {
            return null;
        }
        return encryptAES(data, toKey(key.getBytes(StandardCharsets.UTF_8), AES), iv);
    }

    /**
     * AES/CBC/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @param iv   偏移量
     * @return 加密数据, 返回null表示输入数据有误
     */
    public static byte[] encryptAES(String data, Key key, byte[] iv) throws Exception {
        if (isEmpty(data) || null == key || isEmpty(iv)) {
            return null;
        }
        return encryptAES(data.getBytes(StandardCharsets.UTF_8), key, iv);
    }

    /**
     * AES/CBC/PKCS5Padding加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @param iv   偏移量
     * @return 加密数据, 返回null表示输入数据有误
     */
    public static byte[] encryptAES(byte[] data, Key key, byte[] iv) throws Exception {
        if (isEmpty(data) || null == key || isEmpty(iv)) {
            return null;
        }
        // 实例化
        Cipher cipher = Cipher.getInstance(AES_CBC_PKCS_5);
        // 初始化,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        // 执行操作
        return cipher.doFinal(data);
    }


    /**
     * AES/CBC/PKCS5Padding解密
     *
     * @param base64Data   base64后待解密数据
     * @param base64Key    bas64后密钥
     * @param base64ivKey  bas64后偏移量
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static String decryptAESByBase64Key(String base64Data, String base64Key, String base64ivKey) throws Exception {
        if (isEmpty(base64Data) || isEmpty(base64Key) || isEmpty(base64ivKey)) {
            return null;
        }
        byte[] bytes = decryptAES(Base64.decodeBase64(base64Data), toKey(base64Key, AES), Base64.decodeBase64(base64ivKey));
        if (null == bytes) {
            return null;
        }
        return new String(bytes, StandardCharsets.UTF_8);
    }

    /**
     * AES/CBC/PKCS5Padding解密
     *
     * @param base64Data base64后待解密数据
     * @param key  密钥
     * @param iv   偏移量
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static byte[] decryptAES(String base64Data, String key, String iv) throws Exception {
        if (isEmpty(base64Data) || isEmpty(key) || isEmpty(iv)) {
            return null;
        }
        return decryptAES(Base64.decodeBase64(base64Data), toKey(key.getBytes(StandardCharsets.UTF_8), AES), iv.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * AES/CBC/PKCS5Padding解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @param iv   偏移量
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static byte[] decryptAES(byte[] data, Key key, byte[] iv) throws Exception {
        if (isEmpty(data) || null == key || isEmpty(iv)) {
            return null;
        }
        // 实例化
        Cipher cipher = Cipher.getInstance(AES_CBC_PKCS_5);
        // 初始化,设置为加密模式
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        // 执行操作
        return cipher.doFinal(data);
    }

    /**
     * DES加密
     * @param data      待加密数据
     * @param password  密钥
     * @return 加密数据(经过base64转换), 返回null表示输入数据有误
     */
    public static String encryptDES(String data, String password) throws Exception {
        if (isEmpty(data) || isEmpty(password)) {
            return null;
        }
        Key key = toKey(password.getBytes(StandardCharsets.UTF_8), DES);
        // 实例化
        Cipher cipher = Cipher.getInstance(DES);
        // 初始化,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, key, new SecureRandom());
        // 执行操作
        return Base64.encodeBase64String(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
    }

    /**
     * DES解密
     * @param base64Data      待解密数据
     * @param password  密钥
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static String decryptDES(String base64Data, String password) throws Exception {
        if (isEmpty(base64Data) || isEmpty(password)) {
            return null;
        }
        Key key = toKey(password.getBytes(StandardCharsets.UTF_8), DES);
        // 实例化
        Cipher cipher = Cipher.getInstance(DES);
        // 初始化,设置为加密模式
        cipher.init(Cipher.DECRYPT_MODE, key, new SecureRandom());
        // 执行操作
        return new String(cipher.doFinal(Base64.decodeBase64(base64Data)), StandardCharsets.UTF_8);
    }

    /**
     * RSA加密<br>
     * RSA密钥长度{@link #RSA_KEY_SIZE}
     * @param data      待加密数据
     * @param base64Key  base64后密钥
     * @return 加密数据(经过base64转换), 返回null表示输入数据有误
     */
    public static String encryptByPublicKey(String data, String base64Key) throws Exception {
        return encryptByPublicKey(data, base64Key, RSA_KEY_SIZE);
    }

    /**
     * RSA加密
     * @param data      待加密数据
     * @param base64Key  base64后密钥
     * @param rsaKeySize RSA密钥长度
     * @return 加密数据(经过base64转换), 返回null表示输入数据有误
     */
    public static String encryptByPublicKey(String data, String base64Key, int rsaKeySize) throws Exception {
        if (isEmpty(data) || isEmpty(base64Key)) {
            return null;
        }
        //初始化公钥,根据给定的编码密钥创建一个新的 X509EncodedKeySpec。
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(base64Key));
        PublicKey publicKey = KeyFactory.getInstance(RSA).generatePublic(x509EncodedKeySpec);
        // 实例化
        Cipher cipher = Cipher.getInstance(RSA);
        // 初始化,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        // 执行操作
        return rsaEncrypt(cipher, data, rsaKeySize);
    }

    /**
     * RSA加密<br>
     * RSA密钥长度{@link #RSA_KEY_SIZE}
     * @param data      待加密数据
     * @param base64Key  base64后密钥
     * @return 加密数据(经过base64转换), 返回null表示输入数据有误
     */
    public static String encryptByPrivateKey(String data, String base64Key) throws Exception {
        return encryptByPrivateKey(data, base64Key, RSA_KEY_SIZE);
    }

    /**
     * RSA加密
     * @param data      待加密数据
     * @param base64Key  base64后密钥
     * @param rsaKeySize RSA密钥长度
     * @return 加密数据(经过base64转换), 返回null表示输入数据有误
     */
    public static String encryptByPrivateKey(String data, String base64Key, int rsaKeySize) throws Exception {
        if (isEmpty(data) || isEmpty(base64Key)) {
            return null;
        }
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(base64Key));
        PrivateKey privateKey = KeyFactory.getInstance(RSA).generatePrivate(pkcs8KeySpec);
        // 实例化
        Cipher cipher = Cipher.getInstance(RSA);
        // 初始化,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        // 执行操作
        return rsaEncrypt(cipher, data, rsaKeySize);
    }

    /**
     * rsa分段加密
     * @param cipher     Cipher
     * @param data       待加密数据
     * @param rsaKeySize RSA密钥长度
     * @return 加密后数据
     * @throws Exception 异常
     */
    private static String rsaEncrypt(Cipher cipher, String data, int rsaKeySize) throws Exception {
        // 分段加密
        int MAX_ENCRYPT_BLOCK = rsaKeySize / 8 - 11;
        // URLEncoder编码解决中文乱码问题
        byte[] bytes = URLEncoder.encode(data, StandardCharsets.UTF_8.name()).getBytes(StandardCharsets.UTF_8);
        // 加密时超过117字节就报错。为此采用分段加密的办法来加密
        byte[] enBytes = null;
        for (int i = 0; i < bytes.length; i += MAX_ENCRYPT_BLOCK) {
            // 注意要使用2的倍数，否则会出现加密后的内容再解密时为乱码
            byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(bytes, i, i + MAX_ENCRYPT_BLOCK));
            enBytes = ArrayUtils.addAll(enBytes, doFinal);
        }
        return Base64.encodeBase64String(enBytes);
    }

    /**
     * RSA解密<br>
     * RSA密钥长度{@link #RSA_KEY_SIZE}
     * @param base64Data 待解密数据
     * @param base64Key  base64后密钥
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static String decryptByPublicKey(String base64Data, String base64Key) throws Exception {
        // 执行操作
        return decryptByPublicKey(base64Data, base64Key, RSA_KEY_SIZE);
    }

    /**
     * RSA解密
     * @param base64Data 待解密数据
     * @param base64Key  base64后密钥
     * @param rsaKeySize RSA密钥长度
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static String decryptByPublicKey(String base64Data, String base64Key, int rsaKeySize) throws Exception {
        if (isEmpty(base64Data) || isEmpty(base64Key)) {
            return null;
        }
        //初始化公钥,根据给定的编码密钥创建一个新的 X509EncodedKeySpec。
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(base64Key));
        PublicKey publicKey = KeyFactory.getInstance(RSA).generatePublic(x509EncodedKeySpec);
        // 实例化
        Cipher cipher = Cipher.getInstance(RSA);
        // 初始化,设置为加密模式
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        // 执行操作
        return rsaDecrypt(cipher, Base64.decodeBase64(base64Data), rsaKeySize);
    }

    /**
     * RSA解密<br>
     * RSA密钥长度{@link #RSA_KEY_SIZE}
     * @param base64Data 待解密数据
     * @param base64Key  base64后密钥
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static String decryptByPrivateKey(String base64Data, String base64Key) throws Exception {
        return decryptByPrivateKey(base64Data, base64Key, RSA_KEY_SIZE);
    }

    /**
     * RSA解密
     * @param base64Data 待解密数据
     * @param base64Key  base64后密钥
     * @param rsaKeySize RSA密钥长度
     * @return 解密数据, 返回null表示输入数据有误
     */
    public static String decryptByPrivateKey(String base64Data, String base64Key, int rsaKeySize) throws Exception {
        if (isEmpty(base64Data) || isEmpty(base64Key)) {
            return null;
        }
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(base64Key));
        // 生成私钥
        PrivateKey privateKey = KeyFactory.getInstance(RSA).generatePrivate(pkcs8KeySpec);
        // 实例化
        Cipher cipher = Cipher.getInstance(RSA);
        // 初始化,设置为加密模式
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // 执行操作
        return rsaDecrypt(cipher, Base64.decodeBase64(base64Data), rsaKeySize);
    }

    /**
     * rsa分段解密
     * @param cipher     Cipher
     * @param bytes      待解密数据
     * @param rsaKeySize RSA密钥长度
     * @return 解密后数据
     * @throws Exception 异常
     */
    private static String rsaDecrypt(Cipher cipher, byte[] bytes, int rsaKeySize) throws Exception {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            int MAX_DECRYPT_BLOCK = rsaKeySize / 8;

            int inputLen = bytes.length;
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            return URLDecoder.decode(new String(out.toByteArray(), StandardCharsets.UTF_8), StandardCharsets.UTF_8.name());
        }
    }

    /**
     * HmacSHA1加密
     * @param data      待加密数据
     * @param password  密钥
     * @return 加密数据(十六进制字符串形式密文,大写), 返回null表示输入数据有误
     */
    public static String hmacSHA1(String data, String password) throws Exception {
        return hmacSHA1(data, password, false);
    }

    /**
     * HmacSHA1加密
     * @param data      待加密数据
     * @param password  密钥
     * @param toLowerCase true:十六进制字符串形式小写;false:十六进制字符串形式大写
     * @return 加密数据(十六进制字符串形式密文), 返回null表示输入数据有误
     */
    public static String hmacSHA1(String data, String password, final boolean toLowerCase) throws Exception {
        if (isEmpty(data) || isEmpty(password)) {
            return null;
        }
        // 执行操作
        byte[] bytes = hmacSHA1(data.getBytes(StandardCharsets.UTF_8), password.getBytes(StandardCharsets.UTF_8));
        if (null == bytes) {
            return null;
        }
        return Hex.encodeHexString(bytes, toLowerCase);
    }

    /**
     * HmacSHA1加密
     * @param data      待加密数据
     * @param password  密钥
     * @return 加密数据
     */
    public static byte[] hmacSHA1(byte[] data, byte[] password) throws Exception {
        if (isEmpty(data) || isEmpty(password)) {
            return null;
        }
        Key key = toKey(password, HMAC_SHA1);
        // 实例化
        Mac mac = Mac.getInstance(HMAC_SHA1);
        // 初始化,设置为加密模式
        mac.init(key);
        // 执行操作
        return mac.doFinal(data);
    }

    /**
     * SHA1WithRSA
     * @param data      待加密数据
     * @param base64Key  base64后密钥
     * @return 加密数据(经过base64转换), 返回null表示输入数据有误
     */
    public static String sha1WithRSAByPrivateKey(String data, String base64Key) throws Exception {
        if (isEmpty(data) || isEmpty(base64Key)) {
            return null;
        }
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(base64Key));
        PrivateKey privateKey = KeyFactory.getInstance(RSA).generatePrivate(pkcs8KeySpec);
        // 实例化
        Signature signature = Signature.getInstance(SHA_1_WITH_RSA);
        signature.initSign(privateKey);
        // 执行操作
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        return Base64.encodeBase64String(signature.sign());
    }

    /**
     * 转换密钥
     * @param base64Key base64后密钥
     * @param algorithm 加密算法 AES/DES
     * @return Key 密钥
     */
    private static Key toKey(String base64Key, String algorithm) {
        // 实例化AES密钥材料
        return toKey(Base64.decodeBase64(base64Key), algorithm);
    }

    /**
     * 转换密钥
     * @param bytes 密钥
     * @param algorithm 加密算法 AES/DES
     * @return Key 密钥
     */
    private static Key toKey(byte[] bytes, String algorithm) {
        // 实例化AES密钥材料
        return new SecretKeySpec(bytes, algorithm);
    }

    /**
     * 判断字符串是否为空(不包括空字符串)
     * @param cs 要判断字符串
     * @return true:空字符串
     */
    private static boolean isEmpty(final CharSequence cs) {
        return cs == null || cs.length() == 0;
    }

    /**
     * 判断字数组是否为空(不包括包含空格的数组)
     * @param bytes 要判断数组
     * @return true:空数组
     */
    private static boolean isEmpty(final byte[] bytes) {
        return bytes == null || bytes.length == 0;
    }

    /**
     * 生成aes密钥
     * @return aes密钥(经过base64转换)
     */
    public static String initAesKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
        // 长度
        keyGenerator.init(AES_KEY_SIZE);

        SecretKey secretKey = keyGenerator.generateKey();

        return Base64.encodeBase64String(secretKey.getEncoded());
    }

    /**
     * 生成aes偏移量
     * @return aes偏移量(经过base64转换)
     */
    public static String initIv() {
        byte[] bytes = RandomStringUtils.randomAlphanumeric(16).getBytes(StandardCharsets.UTF_8);
        return Base64.encodeBase64String(new IvParameterSpec(bytes).getIV());
    }

    /**
     * 生成des密钥
     * @return des密钥
     */
    public static String initDesKey() {
        return RandomStringUtils.randomAlphanumeric(8);
    }

    /**
     *  生成rsa密钥
     * @return rsa密钥对;map的key包含privateKey和publicKey
     * @throws Exception 系统异常
     */
    public static Map<String, String> initRsaKey() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA);

        keyPairGenerator.initialize(RSA_KEY_SIZE);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        String privateKey = Base64.encodeBase64String(keyPair.getPrivate().getEncoded());
        String publicKey = Base64.encodeBase64String(keyPair.getPublic().getEncoded());

        Map<String, String> keyMap = new HashMap<>();
        keyMap.put("privateKey", privateKey);
        keyMap.put("publicKey", publicKey);
        return keyMap;
    }
}
